# coding:utf-8

"""
CopyRight(c)  2017-09-15  Fraplus Corp

Author: Weilin Shen, Xiaodong.yang
Email:  xiaodong.yang@unidt.com
Functions:

we chat server

dependence package:

fralog
handler

"""
import sys
from rq import Connection, Worker
from redis import Redis

import json
import requests
from settings import *


class ResultHandler:
    def feature2ocean(data, mode='feature'):
        dic = dict()
        dic['mode'] = mode
        dic['data'] = data
        url = 'http://'+OCEAN_IP+':8178/ocean?jstr=' + json.dumps(dic)
        q = requests.get(url=url).content.decode()
        return json.loads(q)

    def calculate_big_five_score(self, scoring, data=None):
        '''

        :param self:
        :param scoring: [1,2R,3,4R]
        :param data: 问卷客户回答答案
        :return:
        '''
        score = 0.0
        score_item = scoring
        try:
            for each in score_item:
                if cache_question_polor.get(each) is not None:
                    # if "R" not in each:  # "R" 此题为反向计分题，不包含 "R" 为正向计分题
                    resp = data[each]  # self.get_argument('q' + str(index))
                    # log.debug('%s' % (resp))
                    response_answer = resp['answer']
                    if response_answer == 'A':  # 选 A 得1分
                        response_answer = 1
                    elif response_answer == 'B':
                        response_answer = 2
                    elif response_answer == 'C':
                        response_answer = 3
                    elif response_answer == 'D':
                        response_answer = 4
                    elif response_answer == 'E':
                        response_answer = 5
                    else:
                        response_answer = 0
                else:  # 反向计分题
                    each = each.replace("R", "")
                    resp = data[each]  # self.get_argument('q' + str(abs(index)))
                    response_answer = resp['answer']
                    if response_answer == 'A':  # 选 A 得5分
                        response_answer = 5
                    elif response_answer == 'B':
                        response_answer = 4
                    elif response_answer == 'C':
                        response_answer = 3
                    elif response_answer == 'D':
                        response_answer = 2
                    elif response_answer == 'E':
                        response_answer = 1
                    else:
                        response_answer = 0
                score += response_answer
            return score / len(scoring)  # 得分 介于 1-5
        except Exception as e:
            print(e)
            return 0

    def give_score_detail(self, raw, norm_mean, norm_sd, dim, code):
        global desc_map
        try:
            detail = ''
            title = ''
            desc = desc_map[code][dim]
            if desc is None:
                return ''
            if raw < norm_mean - norm_sd:  # 得分低于常模减去一个标准差，那么这个得分 '低于平均水平'
                detail = desc['l_detail']
                title = desc['l_title']
                direct = -1
            elif raw > norm_mean + norm_sd:
                title = desc['h_title']
                detail = desc['h_detail']
                direct = 1
            else:
                detail = desc.get('mean')
                title = '四面八方无死角'
                direct = 0
            return {'detail': detail, 'title': title, 'direct': direct}
        except Exception as e:
            print(e)
            return {'detail': None, 'title': None, 'direct': None}

    def give_character_score_detail(self, raw, dim='o', code='v28', desc=''):
        global desc_map
        try:
            detail = ''
            title = ''
            desc = desc_map[code][dim]
            if desc is None:
                return ''
            if raw < 5:  # 得分低于常模减去一个标准差，那么这个得分 '低于平均水平'
                detail = desc['l_detail']
                title = desc['l_title']
                direct = -1
            elif raw > 5:
                title = desc['h_title']
                detail = desc['h_detail']
                direct = 1
            else:
                detail = desc.get('mean')
                title = '四面八方无死角'
                direct = 0
            return {'detail': detail, 'title': title, 'direct': direct}
        except Exception as e:
            print(e)
            return {'detail': None, 'title': None, 'direct': None}

    def _process_character_data(self, code, data):
        global desc_map
        global cache_questionid_ruleid
        global cache_select_survey
        # 计算大五人格各个维度的得分
        '''
        大五得分分为 O_beta, O_raw 以及 O_score
        O_beta: 问卷算出的直接得分，大五的归一化后的 beta 系数，这个值会之后记录到数据库，作为这次测验的得分
        O_raw：O_beta 映射到 分值范围 1-5 （模型 by 徐清）
        O_score：网页显示的得分，O_score 是 O_raw 的百分制得分，分值范围 0-100，这个数值只是在网页显示时使用，不会记录到数据库
        '''
        # log.info('开始计算特征问卷的大五.....')
        selected_survey = cache_select_survey[code]
        o_norm_mean = float(selected_survey['O_norm_mean'])
        c_norm_mean = float(selected_survey['C_norm_mean'])
        e_norm_mean = float(selected_survey['E_norm_mean'])
        a_norm_mean = float(selected_survey['A_norm_mean'])
        n_norm_mean = float(selected_survey['N_norm_mean'])
        o_norm_sd = float(selected_survey['O_norm_SD'])
        c_norm_sd = float(selected_survey['C_norm_SD'])
        e_norm_sd = float(selected_survey['E_norm_SD'])
        a_norm_sd = float(selected_survey['A_norm_SD'])
        n_norm_sd = float(selected_survey['N_norm_SD'])
        listdata = []
        questions = cache_select_survey['code']['rule_scoring'].split(',')
        for d, x in data.items():
            if d in questions:
                if (x['answer'] == 'A'):  # 选 A 得1分
                    score = 1
                elif (x['answer'] == 'B'):
                    score = 2
                elif (x['answer'] == 'C'):
                    score = 3
                elif (x['answer'] == 'D'):
                    score = 4
                elif (x['answer'] == 'E'):
                    score = 5
                else:
                    score = 0
                item = {'rule_id': cache_questionid_ruleid[d], 'question_id': d, 'score': score}
                listdata.append(item)
        # response = [{'rule_id': 'b111', 'score': 4}, {'rule_id': 'b11', 'score': 1}, {'rule_id': 'r999', 'score': 5},
        #             {'rule_id': 'r94444', 'score': 5}]
        p = self.feature2ocean(listdata)
        o_score_detail = self.give_charscore_detail(p['O'], o_norm_mean, o_norm_sd, 'o', code=code, desc=desc_map)
        c_score_detail = self.give_charscore_detail(p['C'], c_norm_mean, c_norm_sd, 'c', code=code, desc=desc_map)
        e_score_detail = self.give_charscore_detail(p['E'], e_norm_mean, e_norm_sd, 'e', code=code, desc=desc_map)
        a_score_detail = self.give_charscore_detail(p['A'], a_norm_mean, a_norm_sd, 'a', code=code, desc=desc_map)
        n_score_detail = self.give_charscore_detail(p['N'], n_norm_mean, n_norm_sd, 'n', code=code, desc=desc_map)
        # log.info('特征问卷报告已准备好')

        # 将答案及得分保存到数据库
        response = json.dumps(data)
        response = json.loads(response)
        # code = response['code']
        # del(response['code'])

        bigfive = {}
        bigfive['O'] = p['O']
        bigfive['C'] = p['C']
        bigfive['E'] = p['E']
        bigfive['A'] = p['A']
        bigfive['N'] = p['N']

        norm = {}
        norm['O_norm_mean'] = o_norm_mean
        norm['C_norm_mean'] = c_norm_mean
        norm['E_norm_mean'] = e_norm_mean
        norm['A_norm_mean'] = a_norm_mean
        norm['N_norm_mean'] = n_norm_mean

        response_final = {}
        response_final['code'] = code
        response_final['survey_type'] = 'character'
        response_final['response'] = response
        response_final['bigFive'] = bigfive
        response_final['norm'] = norm

        # 将数据保存到 responses_collection，包含问卷的 code，所有 question 的答案，加上大五各个维度的得分以及常模的五个维度的均值
        # db.responses_collection.insert(response_final)
        #
        # 写库部分进行优化，控制访问后台数据库的次数
        #
        # write_queue.put(response_final)
        ret = []
        resp = {}
        resp['dim'] = 'o'
        resp['score'] = p['O']
        resp['detail'] = o_score_detail
        ret.append(resp)

        resp = {}
        resp['dim'] = 'c'
        resp['score'] = p['C']
        resp['detail'] = c_score_detail
        ret.append(resp)

        resp = {}
        resp['dim'] = 'e'
        resp['score'] = p['E']
        resp['detail'] = e_score_detail
        ret.append(resp)

        resp = {}
        resp['dim'] = 'a'
        resp['score'] = p['A']
        resp['detail'] = a_score_detail
        ret.append(resp)

        resp = {}
        resp['dim'] = 'n'
        resp['score'] = p['N']
        resp['detail'] = n_score_detail
        ret.append(resp)
        # log.info('特征问卷结果已返回，Code:%s'%(code))
        # print(ret)
        return ret


    def _process_standard_data(self, code, data):
        #
        # 判断缓存是否命中
        #
        global desc_map
        global cache_select_survey
        global cache_question_polor
        selected_survey = cache_select_survey[code]
        #     {
        #     'O_scoring': '1,2R',
        #     'C_scoring': '',
        #     'E_scoring': '',
        #     'A_scoring': '',
        #     'N_scoring': '',
        #
        #     'O_norm_mean': '1.1',
        #     'C_norm_mean': '1.1',
        #     'E_norm_mean': '1.1',
        #     'A_norm_mean': '1.1',
        #     'N_norm_mean': '1.1',
        #
        #     'O_norm_SD': '1.1',
        #     'C_norm_SD': '1.1',
        #     'E_norm_SD': '1.1',
        #     'A_norm_SD': '1.1',
        #     'N_norm_SD': '1.1'
        #
        # }

        # global select_survey, db_connect
        # log.info('开始计算人格标准题的OCEAN...')
        o_raw, c_raw, e_raw, a_raw, n_raw = 0.0, 0.0, 0.0, 0.0, 0.0
        # 计算大五人格各个维度的得分
        '''
        大五得分分为 o_raw 以及 o_score
        o_raw：原始得分 分值范围 1-5，这个值会之后记录到数据库，作为这次测验的得分
        o_score：网页显示的得分，o_score 是 o_raw 的百分制得分，分值范围 0-100，这个数值只是在网页显示时使用，不会记录到数据库
        '''
        o_raw = self.calculate_big_five_score(selected_survey['O_scoring'].split(','), data)
        c_raw = self.calculate_big_five_score(selected_survey['C_scoring'].split(','), data)
        e_raw = self.calculate_big_five_score(selected_survey['E_scoring'].split(','), data)
        a_raw = self.calculate_big_five_score(selected_survey['A_scoring'].split(','), data)
        n_raw = self.calculate_big_five_score(selected_survey['N_scoring'].split(','), data)
        try:
            o_norm_mean = float(selected_survey['O_norm_mean'])
            c_norm_mean = float(selected_survey['C_norm_mean'])
            e_norm_mean = float(selected_survey['E_norm_mean'])
            a_norm_mean = float(selected_survey['A_norm_mean'])
            n_norm_mean = float(selected_survey['N_norm_mean'])

            o_norm_sd = float(selected_survey['O_norm_SD'])
            c_norm_sd = float(selected_survey['C_norm_SD'])
            e_norm_sd = float(selected_survey['E_norm_SD'])
            a_norm_sd = float(selected_survey['A_norm_SD'])
            n_norm_sd = float(selected_survey['N_norm_SD'])
        except Exception as e:
            print(e)
            o_norm_mean = 0
            c_norm_mean = 0
            e_norm_mean = 0
            a_norm_mean = 0
            n_norm_mean = 0

            o_norm_sd = 0
            c_norm_sd = 0
            e_norm_sd = 0
            a_norm_sd = 0
            n_norm_sd = 0

        o_score_detail = self.give_score_detail(o_raw, o_norm_mean, o_norm_sd, 'o', code=code)
        c_score_detail = self.give_score_detail(c_raw, c_norm_mean, c_norm_sd, 'c', code=code)
        e_score_detail = self.give_score_detail(e_raw, e_norm_mean, e_norm_sd, 'e', code=code)
        a_score_detail = self.give_score_detail(a_raw, a_norm_mean, a_norm_sd, 'a', code=code)
        n_score_detail = self.give_score_detail(n_raw, n_norm_mean, n_norm_sd, 'n', code=code)
        # log.info('标准问卷的报告已准备好')

        o_score = round(20 * (o_raw - 0), 2)  # 得分从1-5分转为百分制
        c_score = round(20 * (c_raw - 0), 2)
        e_score = round(20 * (e_raw - 0), 2)
        a_score = round(20 * (a_raw - 0), 2)
        n_score = round(20 * (n_raw - 0), 2)

        o_norm_score = round(20 * (o_norm_mean - 0), 2)  # 常模均值从1-5分转为百分制
        c_norm_score = round(20 * (c_norm_mean - 0), 2)
        e_norm_score = round(20 * (e_norm_mean - 0), 2)
        a_norm_score = round(20 * (a_norm_mean - 0), 2)
        n_norm_score = round(20 * (n_norm_mean - 0), 2)
        # 传 大五每个维度的得分及得分说明，另外还有大五每个维度大家的得分（即常模），这些数据在结果页中需要用到。
        # self.render('result.html', o_score=str(o_score), o_score_detail=o_score_detail,
        # c_score=str(c_score), c_score_detail=c_score_detail, e_score=str(e_score),
        #  e_score_detail=e_score_detail, a_score=str(a_score), a_score_detail=a_score_detail,
        #  n_score=str(n_score), n_score_detail=n_score_detail, o_norm_score=str(o_norm_score),
        # c_norm_score=str(c_norm_score), e_norm_score=str(e_norm_score), a_norm_score=str(a_norm_score),
        #  n_norm_score=str(n_norm_score))
        # log.info('标准问卷OCEAN计算完毕！')
        #
        # 调用模型，获取特征
        try:
            zo = (o_raw - o_norm_mean) / o_norm_sd
            zc = (c_raw - c_norm_mean) / c_norm_sd
            ze = (e_raw - e_norm_mean) / e_norm_sd
            za = (a_raw - a_norm_mean) / a_norm_sd
            zn = (n_raw - n_norm_mean) / n_norm_sd
        except Exception as e:
            zo = 0
            zc = 0
            ze = 0
            za = 0
            zn = 0
            print(e)
        params = {'O': zo, 'C': zc, 'E': ze, 'A': za, 'N': zn}

        # ret = qing_xu_fun(params)

        # 将答案及得分保存到数据库
        response_data = json.loads(json.dumps(data))
        # code = response['code']
        # del(response['code'])

        bigfive = dict()
        bigfive['O'] = o_raw
        bigfive['C'] = c_raw
        bigfive['E'] = e_raw
        bigfive['A'] = a_raw
        bigfive['N'] = n_raw
        norm = dict()
        norm['O_norm_mean'] = o_norm_mean
        norm['C_norm_mean'] = c_norm_mean
        norm['E_norm_mean'] = e_norm_mean
        norm['A_norm_mean'] = a_norm_mean
        norm['N_norm_mean'] = n_norm_mean

        response_final = dict()
        response_final['code'] = code
        response_final['survey_type'] = 'standard'
        response_final['response'] = response_data
        response_final['bigFive'] = bigfive
        response_final['norm'] = norm
        response_final['zocean'] = params

        # 将数据保存到 responses_collection，包含问卷的 code，所有 question 的答案，加上大五各个维度的得分以及常模的五个维度的均值
        # db.responses_collection.insert(response_final)
        #
        # 写库部分进行优化，控制访问后台数据库的次数
        #
        # log.info('写库response_final')
        # write_queue.put(response_final)
        ret = []
        resp = dict()
        resp['dim'] = 'o'
        resp['score'] = o_score
        resp['detail'] = o_score_detail
        resp['norm'] = o_norm_score
        resp['zocean'] = params
        ret.append(resp)

        resp = dict()
        resp['dim'] = 'c'
        resp['score'] = c_score
        resp['detail'] = c_score_detail
        resp['norm'] = c_norm_score
        resp['zocean'] = params
        ret.append(resp)

        resp = dict()
        resp['dim'] = 'e'
        resp['score'] = e_score
        resp['detail'] = e_score_detail
        resp['norm'] = e_norm_score
        resp['zocean'] = params
        ret.append(resp)

        resp = dict()
        resp['dim'] = 'a'
        resp['score'] = a_score
        resp['detail'] = a_score_detail
        resp['norm'] = a_norm_score
        resp['zocean'] = params
        ret.append(resp)

        resp = dict()
        resp['dim'] = 'n'
        resp['score'] = n_score
        resp['detail'] = n_score_detail
        resp['norm'] = n_norm_score
        resp['zocean'] = params
        ret.append(resp)
        # log.info('标准问卷的结果已返回, Code:%s'%(code))
        return ret


if __name__ == '__main__':
    testresp = {
        "201": {
            "answer": "D",
            "time": 1.04
        },
        "227": {
            "answer": "A",
            "time": 0.132
        },
        "45": "male",
        "222": {
            "answer": "A",
            "time": 0.063
        },
        "226": {
            "answer": "B",
            "time": 0.198
        },
        "214": {
            "answer": "D",
            "time": 0.083
        },
        "206": {
            "answer": "A",
            "time": 0.051
        },
        "Domtitle": "发现自己",
        "220": {
            "answer": "B",
            "time": 0.024
        },
        "219": {
            "answer": "B",
            "time": 0.032
        },
        "216": {
            "answer": "C",
            "time": 0.114
        },
        "channel": "test",
        "start": "2017-10-20 15:7:10",
        "46": "36-40",
        "202": {
            "answer": "C",
            "time": 0.198
        },
        "209": {
            "answer": "A",
            "time": 0.051
        },
        "204": {
            "answer": "A",
            "time": 0.147
        },
        "221": {
            "answer": "A",
            "time": 0.097
        },
        "207": {
            "answer": "A",
            "time": 0.051
        },
        "scoretime": "",
        "211": {
            "answer": "E",
            "time": 0.1
        },
        "217": {
            "answer": "C",
            "time": 0.082
        },
        "208": {
            "answer": "A",
            "time": 0.065
        },
        "225": {
            "answer": "E",
            "time": 0.065
        },
        "end": "2017-10-20 15:7:20",
        "213": {
            "answer": "D",
            "time": 0.084
        },
        "223": {
            "answer": "E",
            "time": 0.23
        },
        "218": {
            "answer": "B",
            "time": 0.098
        },
        "215": {
            "answer": "D",
            "time": 0.051
        },
        "203": {
            "answer": "B",
            "time": 0.185
        },
        "224": {
            "answer": "E",
            "time": 0.114
        },
        "212": {
            "answer": "E",
            "time": 0.064
        },
        "wechatFrom": "",
        "205": {
            "answer": "A",
            "time": 0.065
        },
        "stat": "test",
        "228": {
            "answer": "E",
            "time": 0.632
        },
        "210": {
            "answer": "E",
            "time": 0.198
        },
        "code": "28",
        "wxid": "oG-Lc1DOp9LOSQq-zp1ClFomMOac"
    }

    response = [{'rule_id': 'b65', 'score': 4}, {'rule_id': 'b950', 'score': 1}, {'rule_id': 'b854', 'score': 5},
                {'rule_id': 'b1', 'score': 5}]
    p = ResultHandler.feature2ocean(response)
    print(p)
    #  1->5 不同意->同意
    # {'C': -0.023735342304335872, 'O': 0.29130345490005083,
    # 'E': 0.8310438062193491, 'A': 0.3002743894218151, 'N': 0.36576004961012804}
    # {'N': nan, 'A': nan, 'O': nan, 'E': nan, 'C': nan}

# q_name = 'wechat'
# if __name__ == '__main__':
#     conn = Redis(host = '127.0.0.1', port = 6379)
#     with Connection(connection=conn):
#         w = Worker(q_name)
#         w.work()
